/**
 @file ctc_cli.c

 @date 2010-8-03

 @version v2.0

  This file contains ctc cli api implementation
*/

#include "ctc_cli.h"

#ifdef SDK_IN_VXWORKS
#include "ioLib.h"
#include "types/vxTypesBase.h"
#endif

#include "stdarg.h"

#define DECIMAL_STRLEN_MIN 1
#define DECIMAL_STRLEN_MAX 10

#undef  ctc_cli_out
#define ctc_cli_out(fmt,...)            ctc_cli_out_basic(fmt,##__VA_ARGS__)

CTC_CLI_OUT_FUNC cli_print_func_ptr = sal_printf;

/* prefix_len == 0: match whole world. */
unsigned char
ctc_cli_get_prefix_item(char** argv, unsigned char argc, char* prefix, unsigned char prefix_len)
{
    unsigned char index = 0;

    while (index < argc)
    {
        if ((prefix_len && !sal_strncmp(argv[index], prefix, prefix_len)) ||
            (!sal_strncmp(argv[index], prefix, sal_strlen(argv[index])) &&
             (sal_strlen(argv[index]) == sal_strlen(prefix))) )
        {
            return index;
        }

        index++;
    }

    return 0xFF;
}

void
ctc_cli_register_print_fun(CTC_CLI_OUT_FUNC func)
{
    cli_print_func_ptr = func;
}

int
ctc_cli_out_ext(ctc_vti_t* vty, const char* fmt, ...)
{
    int i = 0;
    int j = 0;
    char* print_buf = CTC_VTY_CLIENT(vty)? CTC_VTY_CLIENT(vty)->print_buf : g_vty_client.print_buf;
    char* ctc_cli_out_print_buf = CTC_VTY_CLIENT(vty)? CTC_VTY_CLIENT(vty)->ctc_cli_out_print_buf: g_vty_client.ctc_cli_out_print_buf;
    char* print_line = CTC_VTY_CLIENT(vty)? CTC_VTY_CLIENT(vty)->print_line : g_vty_client.print_line;

    va_list ap;

    va_start(ap, fmt);
#ifdef SDK_IN_VXWORKS
    vsprintf(print_buf, fmt, ap);
#else
    vsnprintf(print_buf, 1023, fmt, ap);
#endif
    va_end(ap);
    i = 0;

    while (i < 1023 && j < 512 && print_buf[i] != '\0')
    {
        switch (print_buf[i])
        {
        case '\n':
            print_line[j] = '\0';
            if(g_ctc_vti)
            {
                sal_strcpy(ctc_cli_out_print_buf,print_line);
                sal_strcat(ctc_cli_out_print_buf,"\r\n");

                if (g_ctc_vti->output)
                {
                    g_ctc_vti->output(ctc_cli_out_print_buf, sal_strlen(ctc_cli_out_print_buf), NULL);
                }
                else if (g_ctc_vti->grep && g_ctc_vti->fprintf)
                {
                    g_ctc_vti->grep(g_ctc_vti, ctc_cli_out_print_buf, sal_strlen(ctc_cli_out_print_buf));
                }
                else if (g_ctc_vti->printf)
                {
                    g_ctc_vti->printf(g_ctc_vti, ctc_cli_out_print_buf, sal_strlen(ctc_cli_out_print_buf));
                }
            }
            else
            {
                (* cli_print_func_ptr)("%s\r\n", print_line);
            }
            j = 0;
            break;

        default:
            print_line[j] = print_buf[i];
            j++;
            break;
        }

        i++;
    }

    if (print_buf[i] == '\0')
    {
        print_line[j] = '\0';
        if(g_ctc_vti )
        {
            if (g_ctc_vti->output)
            {
                g_ctc_vti->output(print_line, sal_strlen(print_line), NULL);
            }
            else if (g_ctc_vti->grep && g_ctc_vti->fprintf)
            {
                g_ctc_vti->grep(g_ctc_vti, print_line, sal_strlen(ctc_cli_out_print_buf));
            }
            else if (g_ctc_vti->printf)
            {
                g_ctc_vti->printf(g_ctc_vti, print_line, sal_strlen(print_line) );
            }
        }
        else
        {
            (* cli_print_func_ptr)("%s", print_line);
        }
    }

    return 0;
}


int
ctc_cli_out_basic_shell(uint8 ldev, const char* fmt, ...)
{
    int i = 0;
    int j = 0;
    ctc_vti_t* vty = (vty_client[ldev])? vty_client[ldev]->ctc_vti: g_vty_client.ctc_vti;
    char* print_buf = (vty_client[ldev])? vty_client[ldev]->print_buf : g_vty_client.print_buf;
    char* g_ctc_cli_out_print_buf = (vty_client[ldev])? vty_client[ldev]->ctc_cli_out_print_buf: g_vty_client.ctc_cli_out_print_buf;
    char* print_line = (vty_client[ldev])? vty_client[ldev]->print_line : g_vty_client.print_line;
    
    va_list ap;

    va_start(ap, fmt);
#ifdef SDK_IN_VXWORKS
    vsprintf(print_buf, fmt, ap);
#else
    vsnprintf(print_buf, 1023, fmt, ap);
#endif
    va_end(ap);
    i = 0;
    
    while (i < 1023 && j < 512 && print_buf[i] != '\0')
    {
        switch (print_buf[i])
        {
        case '\n':
            print_line[j] = '\0';
            if(vty)
            {
                sal_strcpy(g_ctc_cli_out_print_buf,print_line);
                sal_strcat(g_ctc_cli_out_print_buf,"\r\n");

                if (vty->output)
                {
                    vty->output(g_ctc_cli_out_print_buf, sal_strlen(g_ctc_cli_out_print_buf), NULL);
                }
                else if (vty->grep && vty->fprintf)
                {
                    vty->grep(vty, g_ctc_cli_out_print_buf, sal_strlen(g_ctc_cli_out_print_buf));
                }
                else if (vty->printf)
                {
                    vty->printf(vty, g_ctc_cli_out_print_buf, sal_strlen(g_ctc_cli_out_print_buf));
                }
            }
            else
            {
                (* cli_print_func_ptr)("%s", print_line);
            }
            j = 0;
            break;

        default:
            print_line[j] = print_buf[i];
            j++;
            break;
        }

        i++;
    }

    if (print_buf[i] == '\0')
    {
        print_line[j] = '\0';
        if(vty)
        {
            if (vty->output)
            {
                vty->output(print_line, sal_strlen(print_line), NULL);
            }
            else if (vty->grep && vty->fprintf)
            {
                vty->grep(vty, print_line, sal_strlen(g_ctc_cli_out_print_buf));
            }
            else if (vty->printf)
            {
                vty->printf(vty, print_line, sal_strlen(print_line) );
            }
        }
        else
        {
            (* cli_print_func_ptr)("%s", print_line);
        }
    }
    return 0;
}

int
ctc_cli_out_basic(const char* fmt, ...)
{
    int i = 0;
    int j = 0;
    ctc_vti_t* vty = g_vty_client.ctc_vti;
    char* print_buf = g_vty_client.print_buf;
    char* g_ctc_cli_out_print_buf = g_vty_client.ctc_cli_out_print_buf;
    char* print_line = g_vty_client.print_line;

    
    va_list ap;

    va_start(ap, fmt);
#ifdef SDK_IN_VXWORKS
    vsprintf(print_buf, fmt, ap);
#else
    vsnprintf(print_buf, 1023, fmt, ap);
#endif
    va_end(ap);
    i = 0;
    
    while (i < 1023 && j < 512 && print_buf[i] != '\0')
    {
        switch (print_buf[i])
        {
        case '\n':
            print_line[j] = '\0';
            if(vty)
            {
                sal_strcpy(g_ctc_cli_out_print_buf,print_line);
                sal_strcat(g_ctc_cli_out_print_buf,"\r\n");

                if (vty->output)
                {
                    vty->output(g_ctc_cli_out_print_buf, sal_strlen(g_ctc_cli_out_print_buf), NULL);
                }
                else if (vty->grep && vty->fprintf)
                {
                    vty->grep(vty, g_ctc_cli_out_print_buf, sal_strlen(g_ctc_cli_out_print_buf));
                }
                else if (vty->printf)
                {
                    vty->printf(vty, g_ctc_cli_out_print_buf, sal_strlen(g_ctc_cli_out_print_buf));
                }
            }
            else
            {
                (* cli_print_func_ptr)("%s", print_line);
            }
            j = 0;
            break;

        default:
            print_line[j] = print_buf[i];
            j++;
            break;
        }

        i++;
    }

    if (print_buf[i] == '\0')
    {
        print_line[j] = '\0';
        if(vty)
        {
            if (vty->output)
            {
                vty->output(print_line, sal_strlen(print_line), NULL);
            }
            else if (vty->grep && vty->fprintf)
            {
                vty->grep(vty, print_line, sal_strlen(g_ctc_cli_out_print_buf));
            }
            else if (vty->printf)
            {
                vty->printf(vty, print_line, sal_strlen(print_line) );
            }
        }
        else
        {
            (* cli_print_func_ptr)("%s\r\n", print_line);
        }
    }
    return 0;
}

int32
ctc_cmd_str2int(char* str, int32* ret)
{
    uint32 i;
    uint32 len;
    uint32 digit;
    uint32 limit, remain;
    uint32 minus = 0;
    uint32 max = 0xFFFFFFFF;
    uint32 total = 0;

    /* Sanify check. */
    if (str == NULL || ret == NULL)
    {
        return 0xFFFFFFFF;
    }

    /* First set return value as error. */
    *ret = -1;

    len = sal_strlen(str);
    if (*str == '+')
    {
        str++;
        len--;
    }
    else if (*str == '-')
    {
        str++;
        len--;
        minus = 1;
        max = max / 2 + 1;

    }

    /*add for suport parser hex format*/
    if (len >= 2 && !sal_memcmp(str, "0x", 2))
    {

        if (len == 2)
        {
            *ret = -1;
            return 0xFFFFFFFF;
        }
        else if (len > 10)
        {
            *ret = -1;
            return 0xFFFFFFFF;
        }

        for (i = 2; i < len; i++)
        {
            if ((*(str + i) <= '9' && *(str + i) >= '0')
                || (*(str + i) <= 'f' && *(str + i) >= 'a')
                || (*(str + i) <= 'F' && *(str + i) >= 'A'))
            {
                /*do nothing*/
            }
            else
            {
                *ret = -1;
                return  0xFFFFFFFF;
            }
        }

        total = sal_strtou32(str, NULL, 16);
    }
    else
    {

        limit = max / 10;
        remain = max % 10;

        if (len < DECIMAL_STRLEN_MIN || len > DECIMAL_STRLEN_MAX)
        {
            *ret = -1;
            return 0xFFFFFFFF;
        }

        for (i = 0; i < len; i++)
        {
            if (*str < '0' || *str > '9')
            {
                *ret = -1;
                return  0xFFFFFFFF;
            }

            digit = *str++ - '0';

            if (total > limit || (total == limit && digit > remain))
            {
                *ret = -1;
                return 0xFFFFFFFF;
            }

            total = total * 10 + digit;
        }
    }

    *ret = 0;
    if (minus && (total == 0))
    {
        *ret = -1;
        return  0xFFFFFFFF;
    }

    if (minus)
    {
        return -total;
    }
    else
    {
        return total;
    }
}

uint32
ctc_cmd_str2uint(char* str, int32* ret)
{
    uint32 i;
    uint32 len;
    uint32 digit;
    uint32 limit, remain;
    uint32 max = 0xFFFFFFFF;
    uint32 total = 0;

    /* Sanify check. */
    if (str == NULL || ret == NULL)
    {
        return 0xFFFFFFFF;
    }

    /* First set return value as error. */
    *ret = -1;

    len = sal_strlen(str);

    /*add for suport parser hex format*/
    if (len >= 2 && !sal_memcmp(str, "0x", 2))
    {
        if (len == 2)
        {
            *ret = -1;
            return 0xFFFFFFFF;
        }
        else if (len > 10)
        {
            *ret = -1;
            return 0xFFFFFFFF;
        }

        for (i = 2; i < len; i++)
        {
            if ((*(str + i) <= '9' && *(str + i) >= '0')
                || (*(str + i) <= 'f' && *(str + i) >= 'a')
                || (*(str + i) <= 'F' && *(str + i) >= 'A'))
            {
                /*do nothing*/
            }
            else
            {
                *ret = -1;
                return 0xFFFFFFFF;
            }
        }

        total = sal_strtou32(str, NULL, 16);
    }
    else
    {

        limit = max / 10;
        remain = max % 10;

        if (len < DECIMAL_STRLEN_MIN || len > DECIMAL_STRLEN_MAX)
        {
            *ret = -1;
            return 0xFFFFFFFF;
        }

        for (i = 0; i < len; i++)
        {
            if (*str < '0' || *str > '9')
            {
                *ret = -1;
                return 0xFFFFFFFF;
            }

            digit = *str++ - '0';

            if (total > limit || (total == limit && digit > remain))
            {
                *ret = -1;
                return 0xFFFFFFFF;
            }

            total = total * 10 + digit;
        }
    }

    *ret = 0;
    return total;
}

uint64
ctc_cmd_str2uint64(char* str, int32* ret)
{
#define UINT64_DECIMAL_STRLEN_MAX 20
    uint32 i;
    uint32 len;
    uint32 digit;
    uint64 limit, remain;
    uint64 max = 0xFFFFFFFFFFFFFFFFULL;
    uint64 total = 0;

    /* Sanify check. */
    if (str == NULL || ret == NULL)
    {
        return 0xFFFFFFFFFFFFFFFFULL;
    }

    /* First set return value as error. */
    *ret = -1;

    len = sal_strlen(str);

    /*add for suport parser hex format*/
    if (len >= 2 && !sal_memcmp(str, "0x", 2))
    {
        if (len == 2)
        {
            *ret = -1;
            return 0xFFFFFFFFFFFFFFFFULL;
        }
        else if (len > 18)
        {
            *ret = -1;
            return 0xFFFFFFFFFFFFFFFFULL;
        }

        for (i = 2; i < len; i++)
        {
            if ((*(str + i) <= '9' && *(str + i) >= '0')
                || (*(str + i) <= 'f' && *(str + i) >= 'a')
                || (*(str + i) <= 'F' && *(str + i) >= 'A'))
            {
                /*do nothing*/
            }
            else
            {
                *ret = -1;
                return 0xFFFFFFFFFFFFFFFFULL;
            }
        }

        total = sal_strtou64(str, NULL, 16);
    }
    else
    {

        limit = max / 10;
        remain = max % 10;

        if (len < DECIMAL_STRLEN_MIN || len > UINT64_DECIMAL_STRLEN_MAX)
        {
            *ret = -1;
            return 0xFFFFFFFFFFFFFFFFULL;
        }

        for (i = 0; i < len; i++)
        {
            if (*str < '0' || *str > '9')
            {
                *ret = -1;
                return 0xFFFFFFFFFFFFFFFFULL;
            }

            digit = *str++ - '0';

            if (total > limit || (total == limit && digit > remain))
            {
                *ret = -1;
                return 0xFFFFFFFFFFFFFFFFULL;
            }

            total = total * 10 + digit;
        }
    }

    *ret = 0;
    return total;
}

int32
ctc_cmd_judge_is_num(char* str)
{
    uint32 i;
    uint32 len;

    /* Sanify check. */
    if (NULL == str)
    {
        return -1;
    }

    len = sal_strlen(str);

    /*add for suport parser hex format*/
    if (len >= 2 && !sal_memcmp(str, "0x", 2))
    {
        if (len == 2)
        {
            return -1;
        }

        for (i = 2; i < len; i++)
        {
            if ((*(str + i) <= '9' && *(str + i) >= '0')
                || (*(str + i) <= 'f' && *(str + i) >= 'a')
                || (*(str + i) <= 'F' && *(str + i) >= 'A'))
            {
                /*do nothing*/
            }
            else
            {
                return -1;
            }
        }
    }
    else
    {
        if (len < DECIMAL_STRLEN_MIN || len > DECIMAL_STRLEN_MAX)
        {
            return -1;
        }

        for (i = 0; i < len; i++)
        {
            if (*str < '0' || *str > '9')
            {
                return -1;
            }
        }
    }

    return 0;
}

void
ctc_uint64_to_str(uint64 src, char dest[UINT64_STR_LEN])
{
    int8 i = UINT64_STR_LEN - 1, j = 0;
    uint64 value, sum;

    sal_memset(dest, 0, UINT64_STR_LEN);
    if (0 == src)
    {
        dest[0] = 48;
        return;
    }

    sum = src;

    while (sum)
    {
        value = sum % 10;
        dest[(uint8)i--] = value + 48;
        if (i < 0)
        {
            break;
        }

        sum = sum / 10;
    }

    /*move the string to the front*/
    for (j = 0; j < (UINT64_STR_LEN - 1 - i); j++)
    {
        dest[(uint8)j] = dest[(uint8)i + (uint8)j + 1];
    }

    for (; j <= UINT64_STR_LEN - 1; j++)
    {
        dest[(uint8)j] = 0;
    }
}

int32
ctc_cmd_str2nint (char *str, int32 *ret, uint32 *val)
{
  uint32 i;
  int32 j;
  uint32 len;
  uint32 digit;
  uint32 limit, remain;
  /*uint32 minus = 0;*/
  uint32 max = 0xFFFFFFFF;
   /*uint32 total = 0;*/
  char tmpstr[10] = "\0";


  /* Sanify check. */
  if (str == NULL || ret == NULL)
  {
     return 0xFFFFFFFF;
  }

  /* First set return value as error. */
  *ret = -1;

  len = sal_strlen (str);
  if (*str == '+')
    {
      str++;
      len--;
    }
  else if (*str == '-')
    {
      str++;
      len--;
      /*minus = 1;*/
      max = max / 2 + 1;
     /*don't suport parser negative integer format by 20091208*/
     return 0xFFFFFFFF;
    }
  /*add for suport parser hex format*/
    if (len >= 2 && !sal_memcmp(str, "0x", 2))
    {

     if(len == 2)
      {
              *ret = -1;
              return 0xFFFFFFFF;
      }

      for(i = 2; i < len; i++)
      {
            if ((*(str+i) <= '9' && *(str+i) >= '0')
              || (*(str+i) <= 'f' && *(str+i) >=  'a')
              || (*(str+i) <= 'F' && *(str+i) >= 'A'))
            {
                 /*do nothing*/
            }
            else
            {
                *ret = -1;
                return 0xFFFFFFFF;
            }

      }
      for(j = len-2, i=0; j > 0; j-=8, i++)
      {
            if (j<8)
            {
                sal_strncpy(tmpstr, str+2, j);
                tmpstr[j] = '\0';
            }
            else
            {
                sal_strncpy(tmpstr, str+len-(i+1)*8, 8);
                tmpstr[8] = '\0';
            }
            val[i] = sal_strtou32(tmpstr, NULL, 16);
      }
       /*total = sal_strtou32(str, NULL, 16);*/
    }
    else
    {

        limit = max / 10;
        remain = max % 10;

        if (len < DECIMAL_STRLEN_MIN || len > DECIMAL_STRLEN_MAX)
        {
            *ret = -1;
            return 0xFFFFFFFF;
        }
        for (i = 0; i < len; i++)
        {
            if (*str < '0' || *str > '9')
            {  
                *ret = -1;
                return 0xFFFFFFFF;
            }    

            digit = *str++ - '0';

            if (val[0]  > limit || (val[0] == limit && digit > remain))
            {    *ret = -1;
                return 0xFFFFFFFF;
            }

            val[0] = val[0] * 10 + digit;
        }
    }

  *ret = 0;
 #if 0 
  if (minus && (val[0] == 0))
      return -1;
  if (minus)
      val[0] = -val[0];
#endif
    return 0;
}


/*
 hex str mapping to array
*/
int32
ctc_cmd_xstr2array (char *str, void *array, uint8 arr_len, uint8 arr_type /* 0-uint32, 1-uint16, 2-uint8 */)
{
    uint32 i;
    int32 j;
    uint32 len;
    char tmpstr[10] = "\0";
    uint8 step = (arr_type == 0 ? 8 : (arr_type == 1 ? 4 : 2));
    char * str_ptr = str;
    uint8* u8_ptr = (uint8 *)array;
    uint16* u16_ptr = (uint16 *)array;
    uint32* u32_ptr = (uint32 *)array;

    /* Sanify check. */
    if (str == NULL || array == NULL)
    return -1;

    len = sal_strlen (str);
    if (*str == '+')
    {
        str_ptr++;
        len--;
    }
    else if (*str == '-')
    {
        return -1;
    }

    if (len >= 2 && !sal_memcmp(str, "0x", 2))
    {
        len -= 2;
        str_ptr += 2;
    }

    for(i = 0; i < len; i++)
    {
        if ((*(str_ptr+i) <= '9' && *(str_ptr+i) >= '0')
          || (*(str_ptr+i) <= 'f' && *(str_ptr+i) >=  'a')
          || (*(str_ptr+i) <= 'F' && *(str_ptr+i) >= 'A'))
        {
             /*do nothing*/
        }
        else
        {
          return -1;
        }
    }
    for(j = len, i=0; (j > 0 && i < arr_len); j-=step, i++)
    {
        if (j<step)
        {
            sal_strncpy(tmpstr, str_ptr, j);
            tmpstr[j] = '\0';
        }
        else
        {
            sal_strncpy(tmpstr, str_ptr, step);
            tmpstr[step] = '\0';
            str_ptr += step;
        }
        if(arr_type == 0)
        {
            u32_ptr[i] = sal_strtou32(tmpstr, NULL, 16);
        }
        else if(arr_type == 1)
        {
            u16_ptr[i] = sal_strtou32(tmpstr, NULL, 16);
        }
        else
        {
            u8_ptr[i] = sal_strtou32(tmpstr, NULL, 16);
        }
    }
    return 0;
}



#ifdef SDK_IN_USERMODE
struct termios termios_old;
#elif defined SDK_IN_VXWORKS
static int termios_fd;
static int termios_old;
static int termios_new;
#endif
void
set_terminal_raw_mode(uint32 mode)
{
    if(CTC_VTI_SHELL_MODE_DEFAULT == mode)
    {
#ifdef SDK_IN_VXWORKS
        termios_fd = ioTaskStdGet(0, STD_IN);
        termios_old = ioctl(ioTaskStdGet(0, STD_IN), FIOGETOPTIONS, 0);
        termios_new = termios_old & ~(OPT_LINE | OPT_ECHO);
        ioctl(ioTaskStdGet(0, STD_IN), FIOSETOPTIONS, termios_new);
#elif defined SDK_IN_USERMODE
        /*system("stty raw -echo");*/
        struct termios terminal_new;
        tcgetattr(0, &terminal_new);
        memcpy(&termios_old, &terminal_new, sizeof(struct termios));
        terminal_new.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
                                  | INLCR | IGNCR | ICRNL | IXON | IXOFF);
        /*
          OPOST (output post-processing) & ISIG (Input character signal generating enabled) need to be set
          terminal_new.c_oflag &= ~OPOST;
          terminal_new.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
          */
        terminal_new.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN);
        terminal_new.c_cflag &= ~(CSIZE | PARENB);
        terminal_new.c_cflag |= CS8;

        tcsetattr(0, TCSANOW, &terminal_new);
#endif
    }
    else
    {
        /* write your code here */
    }
}

void
restore_terminal_mode(uint32 mode)
{
    if(CTC_VTI_SHELL_MODE_DEFAULT == mode)
    {

#ifdef SDK_IN_VXWORKS
        ioctl(ioTaskStdGet(0, STD_IN), FIOSETOPTIONS, termios_old);
#elif defined SDK_IN_USERMODE
        /*system("stty cooked echo");*/
        tcsetattr(0, TCSANOW, &termios_old);
#endif
        ctc_cli_out("\n");
    }
    else
    {
        /* write your code here */
    }
}

extern char*
ctc_cli_get_debug_desc_ext(ctc_vti_t* vty, unsigned char level)
{
    char* debug_level_desc = CTC_VTY_CLIENT(vty)->debug_level_desc;

    sal_memset(debug_level_desc, 0, 63);
    if (level & 0x01)
    {
        sal_strcat(debug_level_desc, "Func/");
    }

    if (level & 0x02)
    {
        sal_strcat(debug_level_desc, "Param/");
    }

    if (level & 0x04)
    {
        sal_strcat(debug_level_desc, "Info/");
    }

    if (level & 0x08)
    {
        sal_strcat(debug_level_desc, "Error/");
    }

    if (sal_strlen(debug_level_desc) != 0)
    {
        debug_level_desc[sal_strlen(debug_level_desc) - 1] = '\0';
    }
    else
    {
        sal_strcpy(debug_level_desc, "None");
    }

    return debug_level_desc;
}

uint32
ctc_cmd_get_value(int32* ret, char* name, char* str, uint32 min, uint32 max, uint8 type)
{
    int32 retv = 0;
    uint32 tmp = 0;
    uint8 j = 0;
    char string[256] = {0};

    sal_strncpy(string, name, (sizeof(string) - 1));
    tmp = ctc_cmd_str2uint((str), &retv);

    if(0 == type)   /*get uint8*/
    {
        if (retv < 0 || tmp > CTC_MAX_UINT8_VALUE || tmp < min || tmp > max)
        {
            ctc_cli_out("%% Invalid %s value\n", name);
            *ret = CLI_ERROR;
            return 0;
        }
    }
    else if(1 == type)  /*get uint16*/
    {
        if (retv < 0 || tmp > CTC_MAX_UINT16_VALUE || tmp < min || tmp > max)
        {
            ctc_cli_out("%% Invalid %s value\n", name);
            *ret = CLI_ERROR;
            return 0;
        }
    }
    else    /*get uint32*/
    {
        if (retv < 0 || tmp > CTC_MAX_UINT32_VALUE || tmp < min || tmp > max)
        {
            ctc_cli_out("%% Invalid %s value\n", name);
            *ret = CLI_ERROR;
            return 0;
        }
    }

    for (j = 0; j < sal_strlen(string); j++)
    {
        (string[j]) = sal_tolower((string[j]));
    }

    *ret = retv;
    return tmp;
}


uint32
ctc_cli_get_array_num(char* str)
{
    char* pos = str;
    uint32 num = 1;
    if (!str || !CTC_CLI_STR_IS_ARRAY_START(str))
        return 0;
    if (sal_strlen(str) == 2)
        return 0;
    while (*pos != ']')
    {
        if (*pos == ',')
        {
            num++;
        }
        pos++;
    }
    return num;
}

int32
ctc_cmd_get_value_array(char* name, char* str, void* arr, uint32  *arr_num, uint8 type)
{
    char* pos = str;
    char* start_pos = 0;
    char* end_pos = 0;
    char val[20] = {0};
    uint32 i = 0;
    int32 ret = 0;
    uint8 repeat_mode = 0;

    if (!arr || *arr_num == 0 || !CTC_CLI_STR_IS_ARRAY_START(str))
    {
        ctc_cli_out("%% Invalid %s value\n", name);
        return CLI_ERROR;
    }
    if (type > 3)
    {
        return CLI_ERROR;
    }

    /* type
      * 0 -- uint8
      * 1 -- uint16
      * 2 -- uint32
      * 3 -- uint64
    **/
    for (;*pos != '\0';pos++)
    {
        if(*pos == '[')    /*the parsing begins from now*/
        {
            start_pos = pos + 1;
        }
        else if(*pos == '@' || *pos == ',' || *pos == ']' || *pos == '#') /*get the end positon of a complete string*/
        {
            end_pos = pos;
            if((end_pos-start_pos) && (end_pos-start_pos) <= 20)
            {
                sal_memset(val, 0, sizeof(val));
                if(!start_pos)
                {
                    return CLI_ERROR;
                }
                sal_strncpy(val, start_pos, end_pos-start_pos); /*extract the string by two postions*/

                if(*pos == '@' || repeat_mode)
                {
                    uint32 repeat_times = 0;
                    uint64 temp_value = 0;
                    /*
                    for @, repeat_times represents the subscript of the next value in the array, its value can be 0 or bigger
                    for repeat_mode(#), this represents the times to repeat the previous value, its value must bigger than 0
                    */
                    repeat_times = ctc_cmd_get_value(&ret, name, val, 0, CTC_MAX_UINT32_VALUE, 2);
                    if(repeat_mode && !ret)
                    {
                        if (repeat_times >= 1 && i >= 1) 
                        {
                            /*the previous value(arr[i-1]) has been repeated once, therefore, the next repeat_times need to minus one*/
                            repeat_times -= 1;
                        }
                        else 
                        {
                            return CLI_ERROR;
                        }

                        if((i + repeat_times) <= *arr_num)
                        {
                            temp_value = (type == 2) ? ((uint32*)arr)[i-1] : ((type == 3) ? ((uint64*)arr)[i-1] : ((type == 1) ? ((uint16*)arr)[i-1] : ((uint8*)arr)[i-1]));
                            for (; repeat_times > 0; repeat_times--)
                            {
                                switch (type)
                                {
                                case 3:
                                    ((uint64*)arr)[i++] = (uint64)temp_value;
                                    break;
                                case 2:
                                    ((uint32*)arr)[i++] = (uint32)temp_value;
                                    break;
                                case 1:
                                    ((uint16*)arr)[i++] = (uint16)temp_value;
                                    break;
                                default:
                                    ((uint8*)arr)[i++] = (uint8)temp_value;
                                    break;
                                }
                            }
                            repeat_mode = 0;
                        }
                        else
                        {
                             return CLI_ERROR;
                        } 
                    }
                    else
                    {
                        /*extract the subscript of the next value in the array*/
                        i = repeat_times;
                    }
                }
                else
                {
                    switch (type)
                    {
                    case 3:
                        ((uint64*)arr)[i++] = ctc_cmd_str2uint64(val, &ret);
                        break;
                    case 2:
                        ((uint32*)arr)[i++] = ctc_cmd_get_value(&ret, name, val, 0, CTC_MAX_UINT32_VALUE, 2);
                        break;
                    case 1:
                        ((uint16*)arr)[i++] = ctc_cmd_get_value(&ret, name, val, 0, CTC_MAX_UINT16_VALUE, 1);
                        break;
                    default:
                        ((uint8*)arr)[i++] = ctc_cmd_get_value(&ret, name, val, 0, CTC_MAX_UINT8_VALUE, 0);
                        break;
                    }
                }
                if (ret != 0)
                {
                    return CLI_ERROR;
                }
            }
            if(*pos == ']' || i >= *arr_num)
            {
               break;
            }
            else if(*pos == '#')
            {
                repeat_mode = 1;
            }
            start_pos = pos + 1;
        }
    }
    *arr_num = i;
    return CLI_SUCCESS;
}


#define CTC_CLI_ERROR_DUMP(op, name)  \
    if (op)\
    {\
        ctc_cli_out("%% Invalid %s value\n", name);\
        return CLI_ERROR;\
    }

#define CTC_CLI_GET_DEC_VALUE(LOOP, V, STR, LEN)   \
{\
    (V) = 0;\
    for (LOOP=0; LOOP<(LEN); LOOP++)   \
    {\
        (V) = (V) * 10 + (STR)[LOOP] - '0';\
    }\
}

int32
ctc_cmd_get_timestamp(char* name, char* str, struct tm* p_user_ts)
{
    uint8  loop = 0;
    CTC_CLI_ERROR_DUMP(!str || !p_user_ts || (sal_strlen(str) < 19), name);
    CTC_CLI_ERROR_DUMP(str[4]!='-' || str[7]!='-' || str[10]!='-' || str[13]!=':' || str[16]!=':', name);
    CTC_CLI_GET_DEC_VALUE(loop, p_user_ts->tm_year, str, 4);
    CTC_CLI_GET_DEC_VALUE(loop, p_user_ts->tm_mon, &str[5], 2);
    CTC_CLI_ERROR_DUMP(p_user_ts->tm_mon > 12, "mon");
    CTC_CLI_GET_DEC_VALUE(loop, p_user_ts->tm_mday, &str[8], 2);
    CTC_CLI_ERROR_DUMP(p_user_ts->tm_mday > 31, "day");
    CTC_CLI_GET_DEC_VALUE(loop, p_user_ts->tm_hour, &str[11], 2);
    CTC_CLI_ERROR_DUMP(p_user_ts->tm_hour > 23, "hour");
    CTC_CLI_GET_DEC_VALUE(loop, p_user_ts->tm_min, &str[14], 2);
    CTC_CLI_ERROR_DUMP(p_user_ts->tm_min > 59, "min");
    CTC_CLI_GET_DEC_VALUE(loop, p_user_ts->tm_sec, &str[17], 2);
    CTC_CLI_ERROR_DUMP(p_user_ts->tm_sec > 59, "sec");
    ctc_cli_out("%04u-%02u-%02u-%02u:%02u:%02u\n", p_user_ts->tm_year, p_user_ts->tm_mon, p_user_ts->tm_mday, p_user_ts->tm_hour, p_user_ts->tm_min, p_user_ts->tm_sec);
    p_user_ts->tm_year -= 1900;
    p_user_ts->tm_mon -= 1;
    return CLI_SUCCESS;
}


